package com.yuer.pream.test.cotroller.server;

import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.TypeReference;
import com.yuer.pream.test.utils.*;
import org.apache.log4j.MDC;
import org.springframework.stereotype.Service;

import java.util.LinkedHashMap;
import java.util.List;
import java.util.Vector;
import java.util.concurrent.*;

/**
 * 类功能描述：</br>
 *
 * @author yuyahao
 * @version 1.0 </p> 修改时间：</br> 修改备注：</br>
 */
@Service
public class MAiTEstServer {


    public static final MdcThreadPoolExecutor executorFirst = MdcThreadPoolExecutor.newWithFixedMdc(MDC.getContext(),31, 31, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingDeque<Runnable>());
    public static final MdcThreadPoolExecutor executorSecond = MdcThreadPoolExecutor.newWithFixedMdc(MDC.getContext(),31, 31, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingDeque<Runnable>());

    public String test(){

        String result = "多线程和单线程数据结果对比正确";

        List<LinkedHashMap<String, Object>> rowsResultList = JSONObject.parseObject(UserPathUserData.dbResult2, new TypeReference<List<LinkedHashMap<String, Object>>>(){});
        Vector<LinkedHashMap<String, Object>> rowsList = new Vector<>();
        rowsList.addAll(rowsResultList);
        final Vector<UserPathStepNode>  groupResultList = new Vector<>();
        CountDownLatch countDownLatch = new CountDownLatch(rowsList.size());
        Vector<String> startZeroEventList = new Vector<String>();
        String startOrEndEvent = "_AppStart";
        rowsList.parallelStream().forEach(item->{
            executorFirst.execute(new Runnable() {
                @Override
                public void run() {
                    try {
                        int step = Integer.parseInt(item.get("step").toString());
                        String p = item.get("path").toString();
                        if(p.contains("NULL")){
                            p = p.replaceAll("NULL", "未知");
                        }
                        p = p.replaceAll("开始事件", startOrEndEvent);
                        String path = p;
                        // 拉取1-开始事件/结束事件作第0步不事件
                        if(PatternUtils.mathFirstStartEvent(p)){
                            String mathZerotStartEvent = getCurrentIndexContectStep(p);
                            if(!startZeroEventList.contains(mathZerotStartEvent)){
                                startZeroEventList.add(mathZerotStartEvent);
                            }
                        }
                        UserPathStepNode userPathStepNode = new UserPathStepNode(path,step,	Integer.parseInt(item.get("session_cnt").toString()));
                        groupResultList.add(userPathStepNode);
                    }catch (Exception e){
                        e.printStackTrace();
                    }finally {
                        countDownLatch.countDown();
                    }
                }
            });

        });
        try {
            countDownLatch.await();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        System.out.println("遍历的集合groupResultList大小 = " +groupResultList.size());

        // TODO: 2022/7/28  下面处理 groupResultList的时候，由于是多线程，向 ConcurrentHashMap<Integer, Vector<UserPathStepNode>>添加数据的时候，会出现数据丢失的情况
        // java8的parallelStream的方式进行处理数据，会出现数据丢失的情况
        ConcurrentHashMap<Integer, Vector<UserPathStepNode>> stepStartSplitMap = forJava8parallelStreamGetResult(groupResultList, startZeroEventList);

        // java线程池的方式进行处理数据，会出现数据丢失的情况
        //ConcurrentHashMap<Integer, Vector<UserPathStepNode>> stepStartSplitMap = forExecutePoolGetResult(groupResultList, startZeroEventList);

        // 单线程执行正确的结果
        ConcurrentHashMap<Integer, Vector<UserPathStepNode>> integerVectorConcurrentHashMap = forEachGetResult(groupResultList, startZeroEventList);

        //两个结果进行比对
        for (Integer key : stepStartSplitMap.keySet()) {
            Vector<UserPathStepNode> stepStartSplitMapValue = stepStartSplitMap.get(key);
            //  System.out.println("Key = " + key + ", Value = " + stepStartSplitMapValue);
            for (Integer preamKey : integerVectorConcurrentHashMap.keySet()) {
                if(preamKey.intValue() == key.intValue()){
                    Vector<UserPathStepNode> integerVectorConcurrentHashMapValue = integerVectorConcurrentHashMap.get(preamKey);
                    if(integerVectorConcurrentHashMapValue.size() != stepStartSplitMapValue.size()){
                        result = "多线程和单线程对的少数据啦： integerVectorConcurrentHashMapValue: "+integerVectorConcurrentHashMapValue.size() + "  stepStartSplitMapValue: " + stepStartSplitMapValue.size();
                        System.out.println(result);
                    }
                }
            }
        }

        // 发现多次执行会打印 多线程和单线程对的少数据啦： integerVectorConcurrentHashMapValue: n  stepStartSplitMapValue: x
        // 说明多线程和单线程对比数据不一致的情况
        return result;
    }

    private  static String  getCurrentIndexContectStep(String step) {
        if(!PatternUtils.mathStrLine(step)){
            return "";
        }
        String[] split = step.split(UserPathConstant.SEPARATION_CHARACTER);
        return  String.format(split[0]+"%s"+split[1],UserPathConstant.SEPARATION_CHARACTER);
    }


    /**
     * 多线程：java8的parallelStream的方式进行处理数据，会出现数据丢失的情况
     * @param groupResultList
     * @param startZeroEventList
     * @return
     */
    private  ConcurrentHashMap<Integer,Vector<UserPathStepNode>>    forJava8parallelStreamGetResult(Vector<UserPathStepNode>  groupResultList , Vector<String> startZeroEventList){

        ConcurrentHashMap<Integer,Vector<UserPathStepNode>> stepStartSplitMap = new ConcurrentHashMap<>();
        Vector<Integer> stepStartSplit = new Vector<>();

        groupResultList.parallelStream().forEach(item ->
                {
                    //System.out.println("计算每一步的节点node信息："+item.getPath()+" ====> " +Integer.valueOf(item.getSessionCnt().toString()));
                    String step = item.getPath();
                    //String stepFirst = getCurrentIndexContectStep(step);
                    // 开始事件和结束事件的对、第一步，由于都是1-x-x ,所以第一步这里设置为0,不是代表实际的步数
                    if(startZeroEventList.contains(step)){
                        if(!stepStartSplitMap.containsKey(0)){
                            Vector<UserPathStepNode> eroEventList = new Vector<>();
                            eroEventList.add(item);
                            stepStartSplitMap.put(Integer.valueOf(0),eroEventList);
                        }else {
                            Vector<UserPathStepNode> perStepList = stepStartSplitMap.get(0);
                            perStepList.add(item);
                        }
                    }else{
                        if(step.contains(UserPathConstant.SEPARATION_CHARACTER)){
                            String[] split = step.split(UserPathConstant.SEPARATION_CHARACTER);
                            int preFix = Integer.parseInt(split[0]);
                            if(!stepStartSplit.contains(preFix)){
                                stepStartSplit.add(preFix);
                            }
                            if(!stepStartSplitMap.containsKey(preFix)){
                                stepStartSplitMap.put(Integer.valueOf(preFix),new Vector<>());
                            }
                            if(stepStartSplitMap.containsKey(preFix)){
                                Vector<UserPathStepNode> perStepList = stepStartSplitMap.get(preFix);
                                perStepList.add(item);
                            }
                        }
                    }
                }
        );

        return stepStartSplitMap;
    }

    /**
     * 多线程：java线程池的方式进行处理数据，会出现数据丢失的情况
     * @param groupResultList
     * @param startZeroEventList
     * @return
     */
    private  ConcurrentHashMap<Integer,Vector<UserPathStepNode>>    forExecutePoolGetResult(Vector<UserPathStepNode>  groupResultList , Vector<String> startZeroEventList){

        ConcurrentHashMap<Integer,Vector<UserPathStepNode>> stepStartSplitMap = new ConcurrentHashMap<>();
        Vector<Integer> stepStartSplit = new Vector<>();
        CountDownLatch countDownLatch = new CountDownLatch(groupResultList.size());

        groupResultList.stream().forEach(item ->
                {
                    executorSecond.execute(new Runnable() {
                        @Override
                        public void run() {
                            try {
                                //System.out.println("计算每一步的节点node信息："+item.getPath()+" ====> " +Integer.valueOf(item.getSessionCnt().toString()));
                                String step = item.getPath();
                                //String stepFirst = getCurrentIndexContectStep(step);
                                // 开始事件和结束事件的对、第一步，由于都是1-x-x ,所以第一步这里设置为0,不是代表实际的步数
                                if(startZeroEventList.contains(step)){
                                    if(!stepStartSplitMap.containsKey(0)){
                                        Vector<UserPathStepNode> eroEventList = new Vector<>();
                                        eroEventList.add(item);
                                        stepStartSplitMap.put(Integer.valueOf(0),eroEventList);
                                    }else {
                                        Vector<UserPathStepNode> perStepList = stepStartSplitMap.get(0);
                                        perStepList.add(item);
                                    }
                                }else{
                                    if(step.contains(UserPathConstant.SEPARATION_CHARACTER)){
                                        String[] split = step.split(UserPathConstant.SEPARATION_CHARACTER);
                                        int preFix = Integer.parseInt(split[0]);
                                        if(!stepStartSplit.contains(preFix)){
                                            stepStartSplit.add(preFix);
                                        }
                                        if(!stepStartSplitMap.containsKey(preFix)){
                                            stepStartSplitMap.put(Integer.valueOf(preFix),new Vector<>());
                                        }
                                        if(stepStartSplitMap.containsKey(preFix)){
                                            Vector<UserPathStepNode> perStepList = stepStartSplitMap.get(preFix);
                                            perStepList.add(item);
                                        }
                                    }
                                }
                            }catch (Exception e){
                                e.printStackTrace();
                            }finally {
                                countDownLatch.countDown();
                            }
                        }
                    });
                }
        );
        try {
            countDownLatch.await();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        return stepStartSplitMap;
    }

    /**
     * 用单线程进行处理，用于对比多线程的结果
     * @param groupResultList
     * @param startZeroEventList
     * @return
     */
    private  ConcurrentHashMap<Integer,Vector<UserPathStepNode>>    forEachGetResult(Vector<UserPathStepNode>  groupResultList , Vector<String> startZeroEventList){

        ConcurrentHashMap<Integer,Vector<UserPathStepNode>> stepStartSplitMap = new ConcurrentHashMap<>();
        Vector<Integer> stepStartSplit = new Vector<>();

        groupResultList.stream().forEach(item ->
                {
                    //System.out.println("计算每一步的节点node信息："+item.getPath()+" ====> " +Integer.valueOf(item.getSessionCnt().toString()));
                    String step = item.getPath();
                    //String stepFirst = getCurrentIndexContectStep(step);
                    // 开始事件和结束事件的对、第一步，由于都是1-x-x ,所以第一步这里设置为0,不是代表实际的步数
                    if(startZeroEventList.contains(step)){
                        if(!stepStartSplitMap.containsKey(0)){
                            Vector<UserPathStepNode> eroEventList = new Vector<>();
                            eroEventList.add(item);
                            stepStartSplitMap.put(Integer.valueOf(0),eroEventList);
                        }else {
                            Vector<UserPathStepNode> perStepList = stepStartSplitMap.get(0);
                            perStepList.add(item);
                        }
                    }else{
                        if(step.contains(UserPathConstant.SEPARATION_CHARACTER)){
                            String[] split = step.split(UserPathConstant.SEPARATION_CHARACTER);
                            int preFix = Integer.parseInt(split[0]);
                            if(!stepStartSplit.contains(preFix)){
                                stepStartSplit.add(preFix);
                            }
                            if(!stepStartSplitMap.containsKey(preFix)){
                                stepStartSplitMap.put(Integer.valueOf(preFix),new Vector<>());
                            }
                            if(stepStartSplitMap.containsKey(preFix)){
                                Vector<UserPathStepNode> perStepList = stepStartSplitMap.get(preFix);
                                perStepList.add(item);
                            }
                        }
                    }
                }
        );

        return stepStartSplitMap;
    }
}
